#include <stdlib.h>
#include "../Server.hpp"

// void CloseCallback(Channel *channel)
// {
//     std::cout << "close: " << channel->Fd() << std::endl;
//     channel->Remove();
//     delete channel;
// }

// void EventCallback(EventLoop *loop, Channel *channel, uint64_t timerid)
// {
//     loop->TimerRefresh(timerid);
//     std::cout << "have an event. " << std::endl;
// }
// void ReadCallback(Channel *channel)
// {
//     char buf[1024] = {0};
//     int ret = ::recv(channel->Fd(), buf, 1023, 0);
//     if (ret < 0)
//         CloseCallback(channel);
//     std::cout << buf << std::endl;
//     channel->EnableWrite();
// }
// void WriteCallback(Channel *channel)
// {
//     const char *data = "get message";
//     int ret = ::send(channel->Fd(), data, strlen(data), 0);
//     if (ret < 0)
//         CloseCallback(channel);
//     channel->DisableWrite();
// }
// void ErrorCallback(Channel *channel)
// {
//     CloseCallback(channel);
// }

// void Accepter(EventLoop *loop, Channel *channel)
// {
//     int fd = ::accept(channel->Fd(), NULL, NULL);
//     if (fd < 0)
//         return;
//     uint64_t timefd = rand() % 10000;
//     Channel *chn = new Channel(loop, fd);
//     chn->SetEventCallback(std::bind(EventCallback, loop, chn, timefd));
//     chn->SetReadCallback(std::bind(ReadCallback, chn));
//     chn->SetWriteCallback(std::bind(WriteCallback, chn));
//     chn->SetErrorCallback(std::bind(ErrorCallback, chn));
//     chn->SetCloseCallback(std::bind(CloseCallback, chn));
//     loop->TimerAdd(timefd, std::bind(CloseCallback, chn), 15);
//     chn->EnableRead();
// }
// int main(int argc, char *argv[])
// {
//     if (argc != 2)
//     {
//         std::cerr << "Usage: " << argv[0] << " local-port" << std::endl;
//         exit(0);
//     }
//     srand(time(0));
//     uint16_t port = std::stoi(argv[1]);
//     Socket srv;
//     srv.CreateServer(port);
//     EventLoop loop;
//     Channel channel(&loop, srv.Fd());
//     channel.SetReadCallback(std::bind(Accepter, &loop, &channel));
//     channel.EnableRead();
//     loop.Start();
//     return 0;
// }

std::unordered_map<uint64_t, PtrConnection> _conns;
EventLoop baseloop;
LoopThreadPool *pool;
uint64_t connfd = 10000;
void ConnectionDestory(const PtrConnection &conn)
{
    _conns.erase(conn->Id());
    std::cout << "closed:id " << conn->Id() << ", fd " << conn->Fd() << std::endl;
}

void OnConnected(const PtrConnection &conn)
{
    std::cout << "New Connection: " << conn.get() << std::endl;
}

void OnMessage(const PtrConnection &conn, Buffer *buf)
{
    std::cout << "message thread id: " << std::this_thread::get_id() << std::endl;
    buf->ConfirmReadSize(buf->ReadAbleSize());
    std::string str = "get message";
    conn->Send(str.c_str(), str.size());
}
// void Accepter(EventLoop *loop, Channel *channel)
// {
//     int fd = ::accept(channel->Fd(), NULL, NULL);
//     if (fd < 0)
//         return;
//     PtrConnection conn(new Connection(connfd, fd, loop));
//     conn->SetMessageCallback(std::bind(OnMessage, std::placeholders::_1, std::placeholders::_2));
//     conn->SetConnectedCallback(std::bind(OnConnected, std::placeholders::_1));
//     conn->SetClosedCallback(std::bind(ConnectionDestory, std::placeholders::_1));
//     conn->EnableInactiveRelease(5);
//     conn->Established();
//     _conns.insert(std::make_pair(connfd, conn));
//     connfd++;
// }
// int main(int argc, char *argv[])
// {
//     if (argc != 2)
//     {
//         std::cerr << "Usage: " << argv[0] << " local-port" << std::endl;
//         exit(0);
//     }
//     uint16_t port = std::stoi(argv[1]);
//     Socket srv;
//     srv.CreateServer(port);
//     EventLoop loop;
//     Channel channel(&loop, srv.Fd());
//     channel.SetReadCallback(std::bind(Accepter, &loop, &channel));
//     channel.EnableRead();
//     loop.Start();
//     return 0;
// }

void NewConnection(int fd)
{
    std::cout << "Connection thread id: " << std::this_thread::get_id() << std::endl;
    PtrConnection conn(new Connection(connfd, fd, pool->NextLoop()));
    conn->SetMessageCallback(std::bind(OnMessage, std::placeholders::_1, std::placeholders::_2));
    conn->SetConnectedCallback(std::bind(OnConnected, std::placeholders::_1));
    conn->SetClosedCallback(std::bind(ConnectionDestory, std::placeholders::_1));
    conn->EnableInactiveRelease(5);
    conn->Established();
    _conns.insert(std::make_pair(connfd, conn));
    connfd++;
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " local-port" << std::endl;
        exit(0);
    }
    uint16_t port = std::stoi(argv[1]);
    pool = new LoopThreadPool(&baseloop);
    pool->SetThreadCount(2);
    pool->Create();
    Acceptor acceptor(&baseloop, port);
    acceptor.SetAcceptCallback(std::bind(NewConnection, std::placeholders::_1));
    acceptor.Listen();
    baseloop.Start();
    return 0;
}